home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
FishMarket 1.0
/
FishMarket v1.0.iso
/
fishies
/
051-075
/
disk_052
/
tek4010
/
kermit.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-05-06
|
20KB
|
838 lines
/*************************************************************
* vt100 terminal emulator - KERMIT protocol support
*
* 860823 DBW - Integrated and rewrote lots of code
* 860811 Steve Drew multi filexfer, bugs, status line ect..
* v2.0 860809 DBW - Major rewrite
* v1.1 860720 DBW - Switches, 80 cols, colors, bug fixes
* v1.0 860712 DBW - First version released
*
*************************************************************/
#define MODULE_KERMIT 1
#include "vt100.h"
#define MAXPACKSIZ 94 /* Maximum msgpkt size */
#define CR 13 /* ASCII Carriage Return */
#define LF 10 /* ASCII line feed */
#define SP 32 /* ASCII space */
#define DEL 127 /* Delete (rubout) */
#define MAXTRY 5 /* Times to retry a msgpkt */
#define MYQUOTE '#' /* Quote character I will use */
#define MYRPTQ '~' /* Repeat quote character */
#define MYPAD 0 /* Number of padding characters I will need */
#define MYPCHAR 0 /* Padding character I need (NULL) */
#define MYEOL '\n' /* End-Of-Line character I need */
#define tochar(ch) ((ch) + ' ')
#define unchar(ch) ((ch) - ' ')
#define ctl(ch) ((ch) ^ 64 )
/* Global Variables */
int
size, /* Size of present data */
osize, /* Size of last data entry */
rpsiz, /* Maximum receive msgpkt size */
spsiz, /* Maximum send msgpkt size */
timint, /* Time interval to wait */
pad, /* How much padding to send */
n, /* Packet number */
tp, /* total packets */
numtry, /* Times this msgpkt retried */
retry, /* total retries */
oldtry, /* Times previous msgpkt retried */
rptflg, /* are we doing repeat quoting */
first, /* is this the first time in a file */
rpt, /* current repeat count */
next, /* what is the next character */
t; /* current character */
long
totbytes; /* total bytes xfered on this file */
char
state, /* Present state of the automaton */
padchar, /* Padding character to send */
eol, /* End-Of-Line character to send */
quote, /* Quote character in incoming data */
rptq, /* Quote character for repeats */
ackpkt[MAXPACKSIZ+20], /* ACK/NAK packet buffer */
msgpkt[MAXPACKSIZ+20], /* Message Packet buffer */
filnam[40]; /* remote file name */
snum[10];
void encode(), decode(), rpar(), spar();
FILE *fp; /* file for send/receive */
int shutdown = 0; /* shut down server after all xfers complete */
char *
getfname(name) /* returns pointer to start of file name from file spec */
char *name;
{
int l;
l = strlen(name);
while(l && name[l] != '/' && name[l] != ':') l--;
if (name[l] == '/' || name[l] == ':') l++;
return(name += l);
}
doksend(file,more)
char *file;
int more;
{
int retval;
ttime = TTIME_LONG;
if (!strcmp(file,"$")) { saybye(); return(2); }
if (file[strlen(file)-1] == '$') {
shutdown = 1;
file[strlen(file)-1] = '\0';
}
if ((fp = fopen(file,"r")) == NULL) {
emits("Cannot open send file\n");
return FALSE;
}
getready(file,more);
emits("SEND");
retval = sendsw();
if (retval) { x = 600; emits("DONE"); }
curmode = 0;
if (shutdown) saybye();
emits("\n");
fclose(fp);
return(retval);
}
dokreceive(file,more)
char *file;
int more;
{
int retval;
ttime = TTIME_LONG;
if (!strcmp(file,"$")) { saybye(); return(2); }
if (file[strlen(file)-1] == '$') {
shutdown = 1;
file[strlen(file)-1] = '\0';
}
if ((fp = fopen(file,"w")) == NULL) {
emits("Cannot open file\n");
return FALSE;
}
getready(file,more);
emits("RECV");
retval = recsw();
if (retval) { x = 600; emits("DONE"); }
curmode = 0;
if (shutdown) saybye();
emits("\n");
fclose(fp);
return(retval);
}
getready(file,more)
char *file;
int more;
{
if (!more) {
emits("Remote file name [");
emits(getfname(file));
emits("]: ");
filename(filnam);
if (filnam[0] == 0) strcpy(filnam,getfname(file));
emits("Type <ESC> to abort transfer\n");
}
else strcpy(filnam,getfname(file));
eatup();
tp = retry = 0; totbytes = 0L; n = numtry = 0;
want_message = FALSE; /* tell readchar no error msgs status bar instead */
statusline();
x = 600;
}
sendsw()
{
char sinit(), sfile(), sdata(), seof(), sbreak();
state = 'S';
while(TRUE) {
switch(state) {
case 'S': state = sinit(); break;
case 'F': state = sfile(); break;
case 'D': state = sdata(); break;
case 'Z': state = seof(); break;
case 'B': state = sbreak(); break;
case 'C': return(TRUE);
case 'A': x = 600;
if (timeout == USERABORT) { sabort(); return(FALSE); }
if (timeout == TIMEOUT) emits("TMOUT");
else emits("ERROR");
return(FALSE);
default: return(FALSE);
}
}
}
char sinit()
{
int num, len;
retry++;
if (numtry++ > MAXTRY) return('A');
spar(msgpkt);
spack('S',n,9,msgpkt);
switch(rpack(&len,&num,ackpkt)) {
case 'N': return(state);
case 'Y': if (n != num) return(state);
rpar(ackpkt);
if (eol == 0) eol = '\n';
if (quote == 0) quote = '#';
numtry = 0;
retry--;
n = (n+1)%64;
return('F');
case 'E': return('A');
case FALSE:if (timeout == USERABORT) state = 'A';
return(state);
default: return('A');
}
}
char sfile()
{
int num, len;
retry++;
if (numtry++ > MAXTRY) return('A');
spack('F',n,strlen(filnam),filnam);
switch(rpack(&len,&num,ackpkt)) {
case 'N':
num = (--num<0 ? 63:num);
if (n != num) return(state);
case 'Y':
if (n != num) return(state);
numtry = 0;
retry--;
n = (n+1)%64;
first = 1;
size = getpkt();
return('D');
case 'E':
return('A');
case FALSE: if (timeout == USERABORT) state = 'A';
return(state);
default: return('A');
}
}
char sdata()
{
int num, len;
retry++;
if (numtry++ > MAXTRY) return('A');
spack('D',n,size,msgpkt);
switch(rpack(&len,&num,ackpkt)) {
case 'N':
num = (--num<0 ? 63:num);
if (n != num) return(state);
case 'Y':
if (n != num) return(state);
numtry = 0;
retry--;
n = (n+1)%64;
if ((size = getpkt()) == 0) return('Z');
return('D');
case 'E':
return('A');
case FALSE: if (timeout == USERABORT) state = 'A';
return(state);
default: return('A');
}
}
char seof()
{
int num, len;
retry++;
if (numtry++ > MAXTRY) return('A');
if (timeout == USERABORT) {
timeout = GOODREAD;
spack('Z',n,1,"D"); /* tell host to discard file */
}
else spack('Z',n,0,msgpkt);
switch(rpack(&len,&num,ackpkt)) {
case 'N':
num = (--num<0 ? 63:num);
if (n != num) return(state);
case 'Y':
if (n != num) return(state);
numtry = 0;
retry--;
n = (n+1)%64;
return('B');
case 'E':
return('A');
case FALSE: return(state);
default: return('A');
}
}
char sbreak()
{
int num, len;
retry++;
if (numtry++ > MAXTRY) return('A');
spack('B',n,0,msgpkt);
switch (rpack(&len,&num,ackpkt)) {
case 'N':
num = (--num<0 ? 63:num);
if (n != num) return(state);
case 'Y':
if (n != num) return(state);
numtry = 0;
retry--;
n = (n+1)%64;
return('C');
case 'E':
return('A');
case FALSE: return(state);
default: return ('A');
}
}
/* timeout equals USERABORT so lets end the file and quit */
/* when host receives 'Z' packet with "D" in data field he */
/* should discard the file. */
sabort()
{
emits("ABORT");
n = (n+1)%64;
retry--;
state = 'Z';
while (state == 'Z') state = seof();
while (state == 'B') state = sbreak();
return(FALSE);
}
recsw()
{
char rinit(), rfile(), rdata(), rbreak();
state = 'R';
while(TRUE) {
switch(state) {
case 'R': state = rinit(); break;
case 'F': state = rfile(); break;
case 'D': state = rdata(); break;
case 'Z': state = rbreak(); break;
case 'C': return(TRUE);
case 'A': x = 600;
if (timeout == USERABORT){/* easy way to cleanly abort
should really send and ACK
with "X" in data field and
wait for host to abort but
not all kermits support
this feature. */
emits("ABORT");
spack('E',n,0,0); /* send an error packet back */
}
else if (timeout == TIMEOUT) emits("TMOUT");
else emits("ERROR");
return(FALSE);
}
}
}
char rinit()
{
int len, num;
retry++;
if (numtry++ > MAXTRY) return('A');
if (server) spack('R',n,strlen(filnam),filnam);
else spack('N',n,0,0);
switch(rpack(&len,&num,msgpkt)) {
case 'S':
rpar(msgpkt);
spar(msgpkt);
spack('Y',n,9,msgpkt);
oldtry = numtry;
numtry = 0;
retry--;
n = (n+1)%64;
return('F');
case 'E':
return('A');
case FALSE:
if (timeout == USERABORT) return('A');
spack('N',n,0,0);
return(state);
default:
return('A');
}
}
char rfile()
{
int num, len;
retry++;
if (numtry++ > MAXTRY) return('A');
switch(rpack(&len,&num,msgpkt)) {
case 'S':
if (oldtry++ > MAXTRY) return('A');
if (num == ((n==0) ? 63:n-1)) {
spar(msgpkt);
spack('Y',num,9,msgpkt);
retry--;
numtry = 0;
return(state);
}
else return('A');
case 'Z':
if (oldtry++ > MAXTRY) return('A');
if (num == ((n==0) ? 63:n-1)) {
spack('Y',num,0,0);
numtry = 0;
retry--;
return(state);
}
else return('A');
case 'F':
if (num != n) return('A');
spack('Y',n,0,0);
oldtry = numtry;
numtry = 0;
retry--;
n = (n+1)%64;
return('D');
case 'B':
if (num != n) return ('A');
spack('Y',n,0,0);
retry--;
return('C');
case 'E':
return('A');
case FALSE:
if (timeout == USERABORT) return('A');
spack('N',n,0,0);
return(state);
default:
return ('A');
}
}
char rdata()
{
int num, len;
retry++;
if (numtry++ > MAXTRY) return('A');
switch(rpack(&len,&num,msgpkt)) {
case 'D':
if (num != n) {
if (oldtry++ > MAXTRY) return('A');
if (num == ((n==0) ? 63:n-1)) {
spack('Y',num,6,msgpkt);
retry--;
numtry = 0;
return(state);
}
else return('A');
}
decode();
spack('Y',n,0,0);
oldtry = numtry;
numtry = 0;
retry--;
n = (n+1)%64;
return('D');
case 'F':
if (oldtry++ > MAXTRY) return('A');
if (num == ((n==0) ? 63:n-1)) {
spack('Y',num,0,0);
numtry = 0;
retry--;
return(state);
}
else return('A');
case 'Z':
if (num != n) return('A');
spack('Y',n,0,0);
n = (n+1)%64;
retry--;
return('Z');
case 'E':
return('A');
case FALSE:
if (timeout == USERABORT) return('A');
spack('N',n,0,0);
return(state);
default:
return('A');
}
}
char rbreak()
{
int num, len;
retry++;
if (numtry++ > MAXTRY) return('A');
switch(rpack(&len,&num,msgpkt)) {
case 'B':
spack('Y',n,0,0);
return('C');
case 'Z':
spack('Y',n,0,0);
return('Z');
case 'E':
return('A');
case FALSE:
spack('N',n,0,0);
return(state);
default:
return('A');
}
}
spack(type,num,len,data)
char type, *data;
int num, len;
{
int i;
char chksum, buffer[100];
register char *bufp;
dostats(type);
bufp = buffer;
for (i=1; i<=pad; i++) sendchar(padchar);
*bufp++ = SOH;
*bufp++ = tochar(len+3);
chksum = tochar(len+3);
*bufp++ = tochar(num);
chksum += tochar(num);
*bufp++ = type;
chksum += type;
for (i=0; i<len; i++) {
*bufp++ = data[i];
chksum += data[i];
}
chksum = (((chksum&0300) >> 6)+chksum)&077;
*bufp++ = tochar(chksum);
*bufp++ = '\r';
*bufp++ = '\n';
*bufp = 0;
sendstring(buffer);
}
rpack(len,num,data)
int *len, *num;
char *data;
{
int i, done;
char type, cchksum, rchksum;
char t = '\0';
do {
t = readchar();
if (timeout != GOODREAD) return(FALSE);
} while (t != SOH);
done = FALSE;
while (!done) {
t = readchar();
if (timeout != GOODREAD) return(FALSE);
if (t == SOH) continue;
cchksum = t;
*len = unchar(t)-3;
t = readchar();
if (timeout != GOODREAD) return(FALSE);
if (t == SOH) continue;
cchksum = cchksum + t;
*num = unchar(t);
t = readchar();
if (timeout != GOODREAD) return(FALSE);
if (t == SOH) continue;
cchksum = cchksum + t;
type = t;
for (i=0; i<*len; i++) {
t = readchar();
if (timeout != GOODREAD) return(FALSE);
if (t == SOH) continue;
cchksum = cchksum + t;
data[i] = t;
}
data[*len] = 0;
t = readchar();
if (timeout != GOODREAD) return(FALSE);
rchksum = unchar(t);
t = readchar();
if (timeout != GOODREAD) return(FALSE);
if (t == SOH) continue;
done = TRUE;
}
dostats(type);
cchksum = (((cchksum&0300) >> 6)+cchksum)&077;
if (cchksum != rchksum) return(FALSE);
return((int)type);
}
getpkt() {
int i,eof;
static char leftover[10] = { '\0', '\0', '\0', '\0', '\0',
'\0', '\0', '\0', '\0', '\0' };
if (first == 1) {
first = 0;
*leftover = '\0';
t = getc(fp);
if (t == EOF) {
first = 1;
return(size = 0);
}
totbytes++;
}
else if (first == -1) {
first = 1;
return(size = 0);
}
for (size = 0; (msgpkt[size] = leftover[size]) != '\0'; size++) ;
*leftover = '\0';
rpt = 0;
eof = 0;
while (!eof) {
next = getc(fp);
if (next == EOF) {
first = -1;
eof = 1;
}
else totbytes++;
osize = size;
encode(t);
t = next;
if (size == spsiz-3) return(size);
if (size > spsiz-3) {
for (i = 0; (leftover[i] = msgpkt[osize+i]) != '\0'; i++) ;
size = osize;
msgpkt[size] = '\0';
return(size);
}
}
return(size);
}
void encode(a)
char a;
{
int a7,b8;
if (p_mode == 1 && a == '\n') {
rpt = 0;
msgpkt[size++] = quote;
msgpkt[size++] = ctl('\r');
if (size <= spsiz-3) osize = size;
msgpkt[size++] = quote;
msgpkt[size++] = ctl('\n');
msgpkt[size] = '\0';
return;
}
if (rptflg) {
if (a == next && (first == 0)) {
if (++rpt < 94) return;
else if (rpt == 94) {
msgpkt[size++] = rptq;
msgpkt[size++] = tochar(rpt);
rpt = 0;
}
}
else if (rpt == 1) {
rpt = 0;
encode(a);
if (size <= spsiz-3) osize = size;
rpt = 0;
encode(a);
return;
}
else if (rpt > 1) {
msgpkt[size++] = rptq;
msgpkt[size++] = tochar(++rpt);
rpt = 0;
}
}
a7 = a & 0177;
b8 = a & 0200;
if ((a7 < SP) || (a7==DEL)) {
msgpkt[size++] = quote;
a = ctl(a);
}
if (a7 == quote) msgpkt[size++] = quote;
if ((rptflg) && (a7 == rptq)) msgpkt[size++] = quote;
msgpkt[size++] = a;
msgpkt[size] = '\0';
}
void decode()
{
USHORT a, a7;
char *buf;
buf = msgpkt;
rpt = 0;
while ((a = *buf++) != '\0') {
if (rptflg) {
if (a == rptq) {
rpt = unchar(*buf++);
a = *buf++;
}
}
if (a == quote) {
a = *buf++;
a7 = a & 0177;
if ((a7 >= 0100 && a7 <= 0137) || a7 == '?') a = ctl(a);
}
if (rpt == 0) rpt = 1;
if (p_mode == 1 && a == '\r') continue;
totbytes += rpt;
for (; rpt > 0; rpt--) putc(a, fp);
}
return;
}
void spar(data)
char data[];
{
data[0] = tochar(MAXPACKSIZ);
data[1] = tochar(TTIME_LONG);
data[2] = tochar(MYPAD);
data[3] = ctl(MYPCHAR);
data[4] = tochar(MYEOL);
data[5] = MYQUOTE;
data[6] = 'N';
data[7] = '1';
data[8] = MYRPTQ;
data[9] = '\0';
}
void rpar(data)
char data[];
{
spsiz = unchar(data[0]);
timint = unchar(data[1]);
pad = unchar(data[2]);
padchar = ctl(data[3]);
eol = unchar(data[4]);
quote = data[5];
rptflg = 0;
if (data[6] == 0) return;
if (data[7] == 0) return;
if (data[8] == 0) return;
rptq = data[8];
rptflg = ((rptq > 040 && rptq < 0100) || (rptq > 0140 && rptq < 0177));
}
saybye()
{
int len,num;
shutdown = 0;
spack('G',n,1,"F"); /* shut down server no more files */
rpack(&len,&num,ackpkt);
}
statusline()
{
emits ("\nFile: Pckt: Pckt No: Retrn: Bytes: Stat: ");
x = 48;
curmode = 1;
emits (filnam);
return(0);
}
dostats(type)
char type;
{
if (type != 'Y' && type != 'N' && type != 'G') {
x = 224;
emit(type);
x = 312;
sprintf(snum,"%4d",n+(tp * 64));
emits(snum);
if (n==63) tp++;
x = 408;
sprintf(snum,"%2d",retry-1);
emits(snum);
x = 488;
sprintf(snum,"%6ld",(long)totbytes);
emits(snum);
}
}
/* allow for multi file xfers separated by commas under kermit and XMODEM */
multi_xfer(name,mode,do_send)
char *name;
int (*mode)();
int do_send;
{
int done = 0;
int status;
char *p;
p = name;
while(*p && *p != ',') p++;
if (*p == '\0') {
done = TRUE;
if (multi == 1) multi++;
}
else multi = 1;
*p = '\0';
status = ((*mode)(name, multi));
if (status == TRUE) {
if (do_send) emits("Sent File: ");
else emits("Received File: ");
emits(name);
emits("\n");
emit(8);
}
else if (status == FALSE)
{
close(fd);
if (do_send) emits("Send Failed: ");
else emits("Receive Failed: ");
emits(name);
emits("\n");
emit(8);
}
if (!done) multi_xfer(++p, mode, do_send);
server = 0;
multi = 0;
}
/* gobble up all garb that we received while getting file name strings */
eatup()
{
while(CheckIO(Read_Request)) {
WaitIO(Read_Request);
BeginIO(Read_Request);
}
}